package com.derbysoft.dswitch.adapter.ihg.dswitch2.translate;

import com.derbysoft.dswitch.adapter.ihg.common.domain.ReservationItem;
import com.derbysoft.dswitch.adapter.ihg.common.repository.ReservationItemRepository;
import com.derbysoft.dswitch.adapter.ihg.common.utils.CollectionUtil;
import com.derbysoft.dswitch.adapter.ihg.common.utils.DateTimeUtils;
import com.derbysoft.dswitch.adapter.ihg.common.utils.EnvironmentUtils;
import com.derbysoft.dswitch.adapter.ihg.dswitch2.service.impl.ReservationIDUtils;
import com.derbysoft.dswitch.adapter.ihg.dswitch3.translate.Translator;
import com.derbysoft.dswitch.adapter.ihg.dswitch3.translate.impl.BadCharacterUtils;
import com.derbysoft.dswitch.adapter.ihg.dswitch3.translate.impl.TranslateHelper;
import com.derbysoft.dswitch.adapter.ihg.dto.*;
import com.derbysoft.dswitch.adapter.ihg.exception.ConfirmNumberNotFoundException;
import com.derbysoft.remote.dswitch.core.GenericRQ;
import com.derbysoft.remote.dswitch.generic.constants.AgeQualifyingType;
import com.derbysoft.remote.dswitch.generic.constants.TransactionActionType;
import com.derbysoft.remote.dswitch.generic.dto.*;
import com.derbysoft.remote.dswitch.hotel.dto.*;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component("hotelReservationRQTranslatorV2")
public class HotelReservationRQTranslatorV2 extends BaseTranslator
        implements Translator<GenericRQ<HotelReservationRQ>, OTAHotelResRQ, Void> {

    public static final String DEFAULT_GUARANTEE_CODE = "GX";
    private static final String MODIFY = "Modify";

    @Autowired
    private ReservationItemRepository reservationItemRepository;

    @Override
    public OTAHotelResRQ translate(GenericRQ<HotelReservationRQ> request, Void aVoid) {
        OTAHotelResRQ hotelReservationRequest = new OTAHotelResRQ();
        setHeader(hotelReservationRequest, request.getHeader());
        if (request.getPayload().getResActionType() == TransactionActionType.MODIFY) {
            hotelReservationRequest.setResStatus(MODIFY);
        }
        HotelReservations hotelReservations = new HotelReservations();
        hotelReservations.getHotelReservation().add(translateHotelReservation(request));
        hotelReservationRequest.setHotelReservations(hotelReservations);
        return hotelReservationRequest;
    }

    private String findConfirmNo(HotelReservationIDDTO hotelReservationIDDTO) {
        ReservationItem reservationItem = reservationItemRepository.loadByErsp(hotelReservationIDDTO.getResIDValue());
        if (reservationItem == null || reservationItem.getConfirmNumber() == null) {
            throw new ConfirmNumberNotFoundException("ersp :" + hotelReservationIDDTO.getResIDValue());
        }
        return reservationItem.getConfirmNumber();
    }

    private HotelReservation translateHotelReservation(GenericRQ<HotelReservationRQ> request) {
        HotelReservationRQ hotelReservationRQ = request.getPayload();
        HotelReservation hotelReservation = new HotelReservation();
        Guests resGuests = new Guests();
        resGuests.getResGuest().add(translateGuest(hotelReservationRQ.getHotelReservation()));
        hotelReservation.setResGuests(resGuests);
        ReservationRoomStays roomStays = new ReservationRoomStays();
        roomStays.getRoomStay().addAll(translateRoomStays(hotelReservationRQ.getHotelReservation()));
        hotelReservation.setRoomStays(roomStays);
        hotelReservation.setRoomStayReservation(true);
        if (request.getPayload().getResActionType() == TransactionActionType.MODIFY) {
            hotelReservation.setResGlobalInfo(createResGlobalInfo(request));
        }
        ResponseType responseType = new ResponseType();
        responseType.setResponse(EnvironmentUtils.getIhgReservationResponseType());
        ReservationRsTpaExtensions reservationRsTpaExtensions = new ReservationRsTpaExtensions();
        reservationRsTpaExtensions.setResponseType(responseType);
        hotelReservation.setTPAExtensions(reservationRsTpaExtensions);
        return hotelReservation;
    }

    private ResGlobalInfo createResGlobalInfo(GenericRQ<HotelReservationRQ> request) {
        ResGlobalInfo resGlobalInfo = new ResGlobalInfo();
        HotelReservationIDs hotelReservationIDs = new HotelReservationIDs();
        HotelReservationID hotelReservationID = new HotelReservationID();
        hotelReservationID.setForGuest(false);
        hotelReservationID.setResIDType("14");
        hotelReservationID.setResIDValue(findConfirmNo(ReservationIDUtils.getErspNo(request.getPayload().getHotelReservationIDs())));
        hotelReservationIDs.getHotelReservationID().add(hotelReservationID);
        resGlobalInfo.setHotelReservationIDs(hotelReservationIDs);
        return resGlobalInfo;
    }

    private List<ReservationRoomStay> translateRoomStays(HotelReservationDTO hotelReservationDTO) {
        List<ReservationRoomStay> roomStays = new ArrayList<ReservationRoomStay>();
        for (ReservationRoomStayDTO reservationRoomStay : hotelReservationDTO.getRoomStays()) {
            roomStays.add(translateRoomStay(reservationRoomStay, hotelReservationDTO));
        }
        return roomStays;
    }

    private ReservationRoomStay translateRoomStay(ReservationRoomStayDTO reservationRoomStay, HotelReservationDTO hotelReservationDTO) {
        ReservationRoomStay roomStay = new ReservationRoomStay();
        roomStay.setBasicPropertyInfo(translateBasicPropertyInfo(hotelReservationDTO.getHotelRef().getCode()));
        roomStay.setTimeSpan(translateTimeSpan(reservationRoomStay.getStayDateRange()));
        roomStay.setGuarantee(translateGuarantee());
        GuestCounts guestCounts = new GuestCounts();
        guestCounts.getGuestCount().addAll(translateGuestCounts(reservationRoomStay));
        roomStay.setGuestCounts(guestCounts);
        RoomTypes roomTypes = new RoomTypes();
        roomTypes.getRoomType().add(translateRoomType(reservationRoomStay));
        roomStay.setRoomTypes(roomTypes);
        RatePlans ratePlans = new RatePlans();
        ratePlans.getRatePlan().add(translateRatePlan(reservationRoomStay));
        roomStay.setRatePlans(ratePlans);
        return roomStay;
    }

    private List<GuestCount> translateGuestCounts(ReservationRoomStayDTO reservationRoomStay) {
        GuestCountDTO adult = (GuestCountDTO) CollectionUtil.find(reservationRoomStay.getGuestCounts(), new Predicate() {
            @Override
            public boolean evaluate(Object object) {
                return ((GuestCountDTO) object).getAgeQualifyingType() == AgeQualifyingType.ADULT;
            }
        });
        GuestCountDTO child = (GuestCountDTO) CollectionUtil.find(reservationRoomStay.getGuestCounts(), new Predicate() {
            @Override
            public boolean evaluate(Object object) {
                return ((GuestCountDTO) object).getAgeQualifyingType() == AgeQualifyingType.CHILD;
            }
        });
        List<GuestCount> guestCounts = new ArrayList<GuestCount>();
        guestCounts.add(TranslateHelper.createAdultGuestCount(adult.getCount()));
        if (child != null && child.getCount() > 0) {
            guestCounts.add(TranslateHelper.createChildGuestCount(child.getCount()));
        }
        return guestCounts;
    }

    private Guarantee translateGuarantee() {
        Guarantee guarantee = new Guarantee();
        guarantee.setGuaranteeCode(DEFAULT_GUARANTEE_CODE);
        return guarantee;
    }

    private RoomType translateRoomType(ReservationRoomStayDTO reservationRoomStay) {
        RoomType roomType = new RoomType();
        roomType.setRoomTypeCode(reservationRoomStay.getRoomTypeCode() + reservationRoomStay.getRatePlanCode());
        roomType.setNumberOfUnits(reservationRoomStay.getNumberOfUnits());
        return roomType;
    }

    private RatePlan translateRatePlan(ReservationRoomStayDTO reservationRoomStay) {
        RatePlan ratePlan = new RatePlan();
        ratePlan.setRatePlanCode(reservationRoomStay.getRatePlanCode());
        return ratePlan;
    }

    private TimeSpan translateTimeSpan(StayDateRangeDTO stayDateRange) {
        TimeSpan timeSpan = new TimeSpan();
        timeSpan.setStart(DateTimeUtils.formatDate(stayDateRange.getCheckInDate()));
        timeSpan.setEnd(DateTimeUtils.formatDate(stayDateRange.getCheckOutDate()));
        return timeSpan;
    }

    private BasicPropertyInfo translateBasicPropertyInfo(String passport) {
        BasicPropertyInfo basicPropertyInfo = new BasicPropertyInfo();
        basicPropertyInfo.setHotelCode(loadHotel(passport).getCooperatorCode());
        return basicPropertyInfo;
    }

    private ResGuest translateGuest(HotelReservationDTO hotelReservationDTO) {
        ResGuest resGuest = new ResGuest();
        Customer customer = null;
        ReservationRoomStayDTO roomStay = hotelReservationDTO.getRoomStays().get(0);
        for (CustomerDTO guest : roomStay.getGuests()) {
            PersonNameDTO personName = guest.getPersonName();
            if (customer == null) {
                customer = new Customer();
                customer.setPersonName(createPersonName(personName));
                customer.setTelephone(translateTelephone(guest.getTelephones()));
                customer.setEmail(translateEmail(guest.getEmails()));
                Address address = null;
                if (CollectionUtil.isNotEmpty(guest.getAddresses())) {
                    address = new Address();
                    address.getAddressLine().add(guest.getAddresses().get(0));
                }
                if (guest.getCountry() != null) {
                    if (address == null) {
                        address = new Address();
                    }
                    CountryName countryName = new CountryName();
                    countryName.setCode(guest.getCountry().getA2Code());
                    address.setCountryName(countryName);
                }
                if (address != null) {
                    customer.setAddress(address);
                }
            } else {
                RelatedTraveler relatedTraveler = new RelatedTraveler();
                relatedTraveler.setPersonName(createPersonName(personName));
                RelatedTravelers relatedTravelers = new RelatedTravelers();
                relatedTravelers.getRelatedTraveler().add(relatedTraveler);
                customer.setRelatedTravelers(relatedTravelers);
            }
        }
        if (customer != null && CollectionUtil.isNotEmpty(roomStay.getGuarantees())) {
            PaymentCardDTO paymentCardDTO = roomStay.getGuarantees().get(0).getPaymentCard();
            if (paymentCardDTO != null) {
                PaymentCard paymentCard = new PaymentCard();
                paymentCard.setCardCode(translateCardCode(paymentCardDTO.getCardCode().getCode()));
                paymentCard.setCardNumber(paymentCardDTO.getCardNumber());
                paymentCard.setExpireDate(paymentCardDTO.getExpireDate());
                PaymentForm paymentForm = new PaymentForm();
                paymentForm.setPaymentCard(paymentCard);
                customer.setPaymentForm(paymentForm);
            }
        }
        Profile profile = new Profile();
        ProfileType profileType = new ProfileType();
        profileType.setCustomer(customer);
        profile.setProfile(profileType);
        Profiles profiles = new Profiles();
        profiles.getProfileInfo().add(profile);
        resGuest.setProfiles(profiles);
        return resGuest;
    }

    private PersonName createPersonName(PersonNameDTO personName) {
        PersonName name = new PersonName();
        name.setGivenName(BadCharacterUtils.filterName(personName.getGivenName()));
        name.setSurname(BadCharacterUtils.filterName(personName.getSurname()));
        return name;
    }

    private String translateCardCode(String code) {
        if (code.equals("AE")) {
            return "AX";
        }
        return code;
    }

    private String translateEmail(List<EmailDTO> emails) {
        if (emails == null) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        for (EmailDTO email : emails) {
            builder.append(email.getValue());
            builder.append(";");
        }
        String result = builder.toString();
        if (StringUtils.isBlank(result)) {
            return null;
        }
        return result.substring(0, result.length() - 1);
    }

    private Telephone translateTelephone(List<TelephoneDTO> telephones) {
        StringBuilder builder = new StringBuilder();
        for (TelephoneDTO telephone : telephones) {
            builder.append(telephone.getNumber());
            builder.append(";");
        }
        String result = builder.toString();
        if (StringUtils.isBlank(result)) {
            return null;
        }
        Telephone telephone = new Telephone();
        telephone.setPhoneNumber(result.substring(0, result.length() - 1));
        return telephone;
    }
}
